package co.edu.uniandes.sd.mundo;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;
import java.util.Date;

import net.jxta.discovery.DiscoveryService;
import net.jxta.document.AdvertisementFactory;
import net.jxta.document.MimeMediaType;
import net.jxta.endpoint.InputStreamMessageElement;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.exception.PeerGroupException;
import net.jxta.id.IDFactory;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupFactory;
import net.jxta.pipe.OutputPipe;
import net.jxta.pipe.OutputPipeEvent;
import net.jxta.pipe.OutputPipeListener;
import net.jxta.pipe.PipeID;
import net.jxta.pipe.PipeService;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.rendezvous.RendezVousService;
import net.jxta.rendezvous.RendezvousEvent;
import net.jxta.rendezvous.RendezvousListener;

public class PipeExample implements Runnable, OutputPipeListener,
		RendezvousListener {
	public final static String SOCKET_ID = "urn:jxta:uuid-59616261646162614E5047205032503393B5C2F6CA7A41FBB0F890173088E79404";

	static PeerGroup netPeerGroup = null;
	private final static String TAG = "PipeListenerMsg";
	private final static String FILENAME = "examplepipe.adv";
	private DiscoveryService discoverySvc;
	private RendezVousService rdvSvc;
	private PipeAdvertisement pipeAdv;
	private PipeService pipeSvc;

	public static void main(String args[]) {
		PipeExample myapp = new PipeExample();
		myapp.startJxta();
		myapp.run();
	}

	// This thread creates (resolves) the output pipe
	// and sends a message once it's resolved
	public synchronized void run() {
		try {
			// create output pipe with listener
			// Send out the first pipe resolve call
			System.out.println("Attempting to create a OutputPipe...");
			pipeSvc.createOutputPipe(pipeAdv, this);
			// send out a second pipe resolution after we connect
			// to a rendezvous
			/*
			if (!rdvSvc.isConnectedToRendezVous()) {
				System.out.println("Waiting for Rendezvous Connection");
				try {
					wait();
					System.out
							.println("Connected to Rendezvous, attempting to a OutputPipe");
					
				} catch (InterruptedException e) {
					// got our notification
				}
			}*/
			pipeSvc.createOutputPipe(pipeAdv, this);
			while(true);
		} catch (IOException e) {
			System.out.println("Error: OutputPipe creation failure");
			e.printStackTrace();
			System.exit(-1);
		}
	}

	// by implementing OutputPipeListener we must define this method
	// that is called when an OutputPipeEvent is received.
	public void outputPipeEvent(OutputPipeEvent event) {
		System.out.println("Got an output pipe event");
		OutputPipe op = event.getOutputPipe();
		Message msg = null;
		// create message, and send it via the output pipe
		try {
			System.out.println("Sending message");
			Date date = new Date(System.currentTimeMillis());
			String myMsg = "Hello from peer " + netPeerGroup.getPeerName()
					+ "[" + date.toString() + "]";
			msg = new Message();
			StringMessageElement sme = new StringMessageElement(TAG, myMsg,
					null);
			
			MessageElement me = new InputStreamMessageElement(TAG, MimeMediaType.TEXT_DEFAULTENCODING, new FileInputStream(new File("data/test.txt")), sme);
			
			msg.addMessageElement(null, me);
			
			op.send(msg);
		} catch (Exception e) {
			System.out.println("Error: failed to send message");
			e.printStackTrace();
			System.exit(-1);
		}
		op.close();
		System.out.println("message sent ");
	}

	/**
	 * Check if we've received a rendezvous connect event
	 */
	public synchronized void rendezvousEvent(RendezvousEvent event) {
		if (event.getType() == event.RDVCONNECT) {
			notify();
		}
	}

	// Starts jxta, and gets the pipe and discovery services
	private void startJxta() {
		try {
			// create and start the default jxta NetPeerGroup
			NetworkManager manager = new NetworkManager(
					NetworkManager.ConfigMode.ADHOC, "PipeExample", new File(
							new File(".cache"), "PipeExample").toURI());
			manager.startNetwork();
			netPeerGroup = manager.getNetPeerGroup();
		} catch (Exception e) {
			// could not instantiate the group, print the stack and exit
			System.out.println("fatal error : group creation failure");
			e.printStackTrace();
			System.exit(-1);
		}
		// get the pipe, discovery, and rendezvous services
		pipeSvc = netPeerGroup.getPipeService();
		discoverySvc = netPeerGroup.getDiscoveryService();
		rdvSvc = netPeerGroup.getRendezVousService();
		// Register a rendezvous listener
		rdvSvc.addListener(this);
		// Read in pipe advertisement from file
		System.out.println("Reading in from file " + FILENAME);
		try {
			FileInputStream is = new FileInputStream(FILENAME);
			pipeAdv = (PipeAdvertisement) AdvertisementFactory
					.newAdvertisement(PipeAdvertisement.getAdvertisementType());
			try {
				PipeID id = (PipeID) IDFactory.fromURI(new URI(SOCKET_ID));
				pipeAdv.setPipeID(id);
				pipeAdv.setName("Mi primer pipe");
				pipeAdv.setType(PipeService.UnicastType);
			} catch (Exception e) {
				e.printStackTrace();
			}
			is.close();
		} catch (Exception e) {
			System.out.println("failed to read/parse pipe advertisement");
			e.printStackTrace();
			System.exit(-1);
		}
	}

}
